Skip to content

Right edge toolbar#16

Merged
FedG-code merged 12 commits into
masterfrom
right-edge-toolbar
Apr 11, 2026
Merged

Right edge toolbar#16
FedG-code merged 12 commits into
masterfrom
right-edge-toolbar

Conversation

@FedG-code

Copy link
Copy Markdown
Owner

No description provided.

Comment thread js/toolbar.js
Comment on lines +29 to +33

function buildToolbar() {
var current = document.documentElement.getAttribute('data-theme') || 'bold';

var toolbar = document.createElement('div');

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Low – PREVIEW object duplicates CSS custom properties

These hex values are a second source of truth alongside --theme-*-accent and the per-theme variable blocks in shared.css. The comment on L25 acknowledges this, but it's easy to forget when tweaking a theme color.

Consider pulling the values from the computed style at runtime instead, so there's only one source to maintain:

function getThemeAccent(themeName) {
  // Apply theme class temporarily to :root to read its CSS vars
  var prev = document.documentElement.getAttribute('data-theme');
  document.documentElement.setAttribute('data-theme', themeName);
  var accent = getComputedStyle(document.documentElement)
    .getPropertyValue('--accent').trim();
  document.documentElement.setAttribute('data-theme', prev);
  return accent;
}

This is admittedly more complex and has a layout-thrash cost — acceptable if called lazily (only when the preview panel first needs a theme). For the current 5-theme hardcoded setup the static object is fine; just worth flagging before the theme count grows.

Comment thread js/toolbar.js
Comment on lines +123 to +126
preview.style.top = Math.max(4, br.top - tr.top + btn.offsetHeight / 2 - 40) + 'px';
preview.classList.add('visible');
});

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Low – innerHTML with string concatenation (safe today, worth documenting)

c values are hardcoded hex strings from the PREVIEW object above, so there's no injection risk in practice. However, the pattern of concatenating values into style="background:..." via innerHTML is fragile — if a chip value ever included a " or ; (e.g. a CSS expression), it could break the attribute boundary.

A safer equivalent that avoids innerHTML entirely:

var chipsContainer = preview.querySelector('.preview-chips');
chipsContainer.innerHTML = '';
p.chips.forEach(function(c) {
  var chip = document.createElement('span');
  chip.className = 'preview-chip';
  chip.style.background = c;  // style.background is safe — no HTML parsing
  chipsContainer.appendChild(chip);
});

element.style.background = value only applies the value as a CSS property; it can't inject markup.

Comment thread js/toolbar.js
}

window.Toolbar = { syncActive: syncActive };
})(); No newline at end of file

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit – missing newline at end of file

All other JS files in the repo end with a newline. Add one here to stay consistent and avoid noisy diffs in future edits.

Comment thread js/toolbar.js
'use strict';

// Desktop default is brutalist, mobile default is bold — default theme sits first in the bar.
var IS_MOBILE = window.matchMedia('(max-width: 768px)').matches;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Low – IS_MOBILE sniffed once at script load

matchMedia('(max-width: 768px)') is evaluated exactly once when the script runs. If a user resizes the window across the 768px breakpoint (or rotates a tablet from landscape to portrait), the THEMES array order won't update — the toolbar renders with whatever order was decided at load time.

This is unlikely to matter in practice (most users don't resize past that breakpoint mid-session), but worth a comment explaining the intentional choice:

// IS_MOBILE is intentionally evaluated once at load — the toolbar order
// is fixed for the session to avoid reordering under the user's cursor.
var IS_MOBILE = window.matchMedia('(max-width: 768px)').matches;

Also note: this 768px breakpoint is now defined in three places — here, in the HTML <head> inline scripts, and in shared.css. If it ever needs changing, all three locations must be updated together.

@claude

claude Bot commented Apr 11, 2026

Copy link
Copy Markdown

Code Review

This PR cleanly replaces the old floating theme-switcher button and plane toggle with a consolidated right-edge toolbar. The refactor is well-scoped — the removal of the old cycling logic in shared.js, the clean setTheme(name) API, and the guard (typeof window.setTheme === 'function') in toolbar.js for the load-order gap all look correct.

What's good

  • Load-order safety: toolbar.js checks window.setTheme exists before calling it; shared.js null-checks window.Toolbar.syncActive. Neither direction has a hard dependency at definition time.
  • Accessibility: role="toolbar", aria-label, aria-pressed on swatch buttons — solid baseline.
  • Default theme logic: The new if (!t) t = matchMedia(...) ? 'bold' : 'brutalist' pattern is an improvement. First-time visitors now get a sensible themed default instead of the raw data-theme="bold" HTML fallback.
  • Hover preview desktop-only gate: (hover: hover) and (pointer: fine) is the right media query to exclude touch devices rather than relying on IS_MOBILE.
  • Plane.js simplification: Removing the bounce timer cluster is a nice cleanup.

Issues

All issues are Low / Nit severity — nothing blocking:

# File Line Issue
1 js/toolbar.js L6 IS_MOBILE sniffed once at load; 768px breakpoint duplicated in 3 places
2 js/toolbar.js L29-33 PREVIEW object duplicates CSS custom properties — maintenance risk
3 js/toolbar.js L123-126 innerHTML + string concat for chip colors (safe today, fragile pattern)
4 js/toolbar.js L152 Missing newline at end of file

See the inline comments for details and suggested fixes.

Out-of-scope observations (pre-existing, not blocking this PR)

  • CDN GSAP scripts (index.html L279-281 and equivalent on project pages) are loaded without Subresource Integrity hashes. If jsDelivr is ever compromised, arbitrary JS would run on visitors. Worth adding integrity + crossorigin attributes in a follow-up.
  • js/analytics.js monkey-patches history.pushState — this creates a load-order dependency and will silently break if any other script also wraps pushState. A spa:navigate custom event dispatched from page-transition.js would be more robust.

@FedG-code
FedG-code merged commit 77658cc into master Apr 11, 2026
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant